/*
    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) 2013  adrien aubry <email>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "Client.h"

ThreadVisibility::ThreadVisibility(Client* cli) : ClientThread(cli, "ThreadVisibility") {
	client = cli;
	ticks = geGetTick();
	cList = 0;
	cVisibleList = 1;
	cVisible = NULL;
}

std::list<Chunk*>* ThreadVisibility::getVisibleChunks(){
	cVisibleList = cList;
	return cVisible;
}

void ThreadVisibility::run(){
	u32 i, j, k;
	float d1 = 0.0;
	float x1 = 0.0;
	float y1 = 0.0;
	float op = 0.0;
	float camcos = 0.0;
	float camsin = 0.0;
	float fovsin = geSin(60 * 0.01745329);
	int list[8192] = { 0 };
	float dist[8192] = { 0.0 };
	bool visible = true;
	while(cVisibleList != cList)geSleep(2);

	camcos = geCos(client->cam->RotH_rad);
	camsin = geSin(client->cam->RotH_rad);
	for(i=0, j=0; i<client->getWorld()->getChunksCount(); i++){
		if(client->getWorld()->getChunks()[i].isVisible() && client->getWorld()->getChunks()[i].getRenderer()->enabled){
			Chunk* chunk = &client->getWorld()->getChunks()[i];
			visible = true;
			d1 = geDistance2D(client->cam->x, client->cam->y, chunk->getX()+8, chunk->getY()+8);
			/*
			if(d1 > (float)world->options.view_distance){
				visible = false;
			}else */
			if(d1 > 32.0){
				x1 = client->cam->x + d1 * camcos;
				y1 = client->cam->y + d1 * camsin;
				op = d1 * fovsin;
				if(geDistance2D(x1, y1, chunk->getX()+8, chunk->getY()+8)-8.0 > op){
					visible = false;
				}
			}
			
			if(visible/* && chunk->getRenderer()->enabled*/){
				list[j] = i;
				dist[j] = d1;
				j++;
				chunk->setRendered(false);
			}
		}
	}
/*
	float view_vec[3] = { client->cam->cX - client->cam->x, client->cam->cY - client->cam->y, client->cam->cZ - client->cam->z };
	geNormalize(view_vec);
	float norm_north[3] = { 1.0, 0.0, 0.0 };
	float norm_south[3] = { -1.0, 0.0, 0.0 };
	float norm_east[3] = { 0.0, 1.0, 0.0 };
	float norm_west[3] = { 0.0, -1.0, 0.0 };
	float norm_up[3] = { 0.0, 0.0, -1.0 };
	float norm_down[3] = { 0.0, 0.0, 1.0 };
	bool dots[6];
	dots[0] = geDotProduct((ge_Vector3f*)view_vec, (ge_Vector3f*)norm_north) >= -geCos((360.0 - 60.0) * 0.01745329);
	dots[1] = geDotProduct((ge_Vector3f*)view_vec, (ge_Vector3f*)norm_south) >= -geCos((360.0 - 60.0) * 0.01745329);
	dots[2] = geDotProduct((ge_Vector3f*)view_vec, (ge_Vector3f*)norm_east) >= -geCos((360.0 - 60.0) * 0.01745329);
	dots[3] = geDotProduct((ge_Vector3f*)view_vec, (ge_Vector3f*)norm_west) >= -geCos((360.0 - 60.0) * 0.01745329);
	dots[4] = geDotProduct((ge_Vector3f*)view_vec, (ge_Vector3f*)norm_up) >= -geCos((360.0 - 60.0) * 0.01745329);
	dots[5] = geDotProduct((ge_Vector3f*)view_vec, (ge_Vector3f*)norm_down) >= -geCos((360.0 - 60.0) * 0.01745329);
*/
	chunks_visible[cList].clear();

	Chunk* curr = NULL;
	float d = 0.0;
	float curr_d = 0.0;
	for(i=0; i<j; i++){
		curr_d = 100000000000000.0;
		curr = NULL;
		for(k=0; k<j; k++){
			Chunk* c = &client->getWorld()->getChunks()[list[k]];
			if(dist[k] >= d && dist[k] < curr_d && c->isRendered() == false){
				curr_d = dist[k];
				curr = c;
			}
		}
		if(curr){
			curr->setRendered(true);
			d = curr_d;
			if(curr->getRenderer()->nVerts > 0){
				chunks_visible[cList].push_front(curr);
			}
		}
	}

/*
	for(i=0, j=0; i<client->getWorld()->getChunksCount(); i++){
		if(client->getWorld()->getChunks()[i].isVisible() && client->getWorld()->getChunks()[i].getRenderer()->enabled){
			Chunk* chunk = &client->getWorld()->getChunks()[i];
			chunk->setRendered(true);
			chunks_visible[cList].push_back(chunk);
		}
	}
*/
	cVisible = &chunks_visible[cList];
	cList = (cList + 1) % 2;
	ticks = geWaitTick(1000/60, ticks);
}

